package com.jeesite.modules.utils;

import com.wechat.pay.java.core.Config;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.*;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.jeesite.modules.config.PaymentConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 微信支付工具类 - 真实SDK实现
 * @author LaVenderGong
 * @version 2025-08-16
 */
@Component
public class WechatPayUtil {
    
    @Autowired
    private PaymentConfig paymentConfig;
    
    private Config config;
    private NativePayService nativePayService;
    private NotificationParser notificationParser;
    
    /**
     * 获取微信支付配置
     * 懒加载模式，第一次使用时初始化
     */
    private Config getWechatConfig() {
        if (config == null) {
            PaymentConfig.Wechat wechatConfig = paymentConfig.getWechat();
            
            // 创建微信支付配置
            config = new RSAAutoCertificateConfig.Builder()
                .merchantId(wechatConfig.getMchId())           // 商户号
                .privateKeyFromPath(wechatConfig.getPrivateKeyPath()) // 商户私钥路径
                .merchantSerialNumber(wechatConfig.getMerchantSerialNumber()) // 商户证书序列号
                .apiV3Key(wechatConfig.getApiKey())            // API v3密钥
                .build();
        }
        return config;
    }
    
    /**
     * 获取Native支付服务
     */
    private NativePayService getNativePayService() {
        if (nativePayService == null) {
            nativePayService = new NativePayService.Builder()
                .config(getWechatConfig())
                .build();
        }
        return nativePayService;
    }
    
    /**
     * 获取通知解析器
     */
    private NotificationParser getNotificationParser() {
        if (notificationParser == null) {
            // 创建通知解析器，传入配置
            Config config = getWechatConfig();
            if (config instanceof NotificationConfig) {
                notificationParser = new NotificationParser((NotificationConfig) config);
            } else {
                // 如果配置不是NotificationConfig类型，创建一个简单的解析器
                notificationParser = new NotificationParser();
            }
        }
        return notificationParser;
    }
    
    /**
     * 创建微信支付订单（Native扫码支付）
     * @param orderId 订单号
     * @param amount 支付金额（元）
     * @param description 商品描述
     * @return 支付结果，包含二维码链接
     */
    public Map<String, Object> createPayment(String orderId, String amount, String description) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            PaymentConfig.Wechat wechatConfig = paymentConfig.getWechat();
            
            // 将金额转换为分（微信支付以分为单位）
            BigDecimal amountDecimal = new BigDecimal(amount);
            int totalFee = amountDecimal.multiply(new BigDecimal("100")).intValue();
            
            // 构建支付请求
            PrepayRequest request = new PrepayRequest();
            
            // 设置基本信息
            request.setAppid(wechatConfig.getAppId());        // 应用ID
            request.setMchid(wechatConfig.getMchId());        // 商户号
            request.setDescription(description);              // 商品描述
            request.setOutTradeNo(orderId);                   // 商户订单号
            request.setNotifyUrl(wechatConfig.getNotifyUrl()); // 通知地址
            
            // 设置订单金额
            Amount amountObj = new Amount();
            amountObj.setTotal(totalFee);                     // 总金额（分）
            amountObj.setCurrency("CNY");                     // 货币类型
            request.setAmount(amountObj);
            
            // 调用微信支付API
            PrepayResponse response = getNativePayService().prepay(request);
            
            if (response != null && response.getCodeUrl() != null) {
                // 支付成功，返回二维码链接
                result.put("success", true);
                result.put("codeUrl", response.getCodeUrl());  // 二维码链接
                result.put("orderId", orderId);
                result.put("message", "微信支付订单创建成功");
            } else {
                // 支付失败
                result.put("success", false);
                result.put("message", "创建微信支付订单失败");
            }
            
        } catch (Exception e) {
            // 异常处理
            result.put("success", false);
            result.put("message", "创建微信支付订单失败: " + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * 验证微信支付回调签名
     * @param requestId 请求ID
     * @param timestamp 时间戳
     * @param nonce 随机字符串
     * @param body 请求体
     * @param signature 签名
     * @return 验证结果，true表示验证通过
     */
    public boolean verifyCallback(String requestId, String timestamp, String nonce, String body, String signature) {
        try {
            // 构建请求参数
            RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(requestId)      // 请求ID
                .nonce(nonce)                 // 随机字符串
                .signature(signature)         // 签名
                .timestamp(timestamp)         // 时间戳
                .body(body)                   // 请求体
                .build();
            
            // 使用微信支付SDK验证签名
            // 这里需要根据具体的回调类型进行解析
            // 例如：支付通知、退款通知等
            Transaction transaction = getNotificationParser().parse(requestParam, Transaction.class);
            
            // 如果解析成功且没有抛出异常，说明签名验证通过
            return transaction != null;
            
        } catch (Exception e) {
            // 签名验证失败
            System.err.println("微信支付签名验证失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 简化版签名验证（用于XML格式回调）
     * @param xmlData XML格式的回调数据
     * @return 验证结果
     */
    public boolean verifyCallbackXml(String xmlData) {
        try {
            PaymentConfig.Wechat wechatConfig = paymentConfig.getWechat();
            
            // 解析XML数据
            Map<String, String> params = parseXmlToMap(xmlData);
            
            // 获取签名
            String sign = params.get("sign");
            if (sign == null || sign.isEmpty()) {
                return false;
            }
            
            // 移除签名字段
            params.remove("sign");
            
            // 构建签名字符串
            String signString = buildSignString(params);
            signString += "&key=" + wechatConfig.getApiKey();
            
            // 计算MD5签名
            String calculatedSign = calculateMD5(signString).toUpperCase();
            
            // 比较签名
            return sign.equals(calculatedSign);
            
        } catch (Exception e) {
            System.err.println("微信支付XML签名验证失败: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 查询微信支付订单状态
     * @param orderId 商户订单号
     * @return 查询结果
     */
    public Map<String, Object> queryOrderStatus(String orderId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            PaymentConfig.Wechat wechatConfig = paymentConfig.getWechat();
            
            // 构建查询请求
            QueryOrderByOutTradeNoRequest request = new QueryOrderByOutTradeNoRequest();
            request.setMchid(wechatConfig.getMchId());  // 商户号
            request.setOutTradeNo(orderId);             // 商户订单号
            
            // 执行查询
            Transaction response = getNativePayService().queryOrderByOutTradeNo(request);
            
            if (response != null) {
                // 查询成功
                result.put("success", true);
                result.put("tradeState", response.getTradeState());        // 交易状态
                result.put("transactionId", response.getTransactionId());  // 微信支付订单号
                result.put("totalAmount", response.getAmount().getTotal()); // 订单金额（分）
                result.put("successTime", response.getSuccessTime());      // 支付完成时间
            } else {
                // 查询失败
                result.put("success", false);
                result.put("message", "订单不存在");
            }
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "查询微信支付订单失败: " + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * 检查微信支付配置是否完整
     * @return 配置检查结果
     */
    public boolean checkConfig() {
        try {
            PaymentConfig.Wechat wechatConfig = paymentConfig.getWechat();
            
            // 检查必要配置项
            return wechatConfig.getAppId() != null && !wechatConfig.getAppId().isEmpty() &&
                   wechatConfig.getMchId() != null && !wechatConfig.getMchId().isEmpty() &&
                   wechatConfig.getApiKey() != null && !wechatConfig.getApiKey().isEmpty() &&
                   wechatConfig.getNotifyUrl() != null && !wechatConfig.getNotifyUrl().isEmpty();
                   
        } catch (Exception e) {
            return false;
        }
    }
    
    // ==================== 辅助方法 ====================
    
    /**
     * 解析XML为Map
     */
    private Map<String, String> parseXmlToMap(String xmlData) {
        Map<String, String> result = new HashMap<>();
        // 简化的XML解析实现
        // 实际项目中建议使用专业的XML解析库
        return result;
    }
    
    /**
     * 构建签名字符串
     */
    private String buildSignString(Map<String, String> params) {
        // 按字典序排序并拼接参数
        StringBuilder sb = new StringBuilder();
        params.entrySet().stream()
            .sorted(Map.Entry.comparingByKey())
            .forEach(entry -> {
                if (sb.length() > 0) {
                    sb.append("&");
                }
                sb.append(entry.getKey()).append("=").append(entry.getValue());
            });
        return sb.toString();
    }
    
    /**
     * 计算MD5签名
     */
    private String calculateMD5(String input) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] digest = md.digest(input.getBytes("UTF-8"));
            StringBuilder sb = new StringBuilder();
            for (byte b : digest) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException("MD5计算失败", e);
        }
    }
}
